iT邦幫忙

2026 iThome 鐵人賽

DAY 6
0

本篇階段:實作挑戰

使用介面:claude.ai(一句提示詞,在對話裡產生完整 Python 專案)


前情

Day 05 做的三個 HTML,共同點是畫面就是產出。網頁打開來能動,題目就算解完了,沒有第二個東西要交。

今天換一個方向。題目本身是演算法,不是畫面,而且是我自己沒寫過、只在論文跟簡報裡看過名字的那種演算法。

想知道的事情很單純:對一個題目只有概念上的理解,沒有實作經驗、沒有現成程式碼可抄,一句話能換回多少東西?

丟出去的提示詞就這一句,沒有規格書、沒有附檔案、沒有補充說明:

幫我建立一個 Python 演算法,主題是利用 ICP (Iterative Closest Point) 或 NDT (Normal Distributions Transform) 去模擬在太空中,登陸艇降落固體行星表面之前,先使用光學感測掃描星球表面,並使用這兩種演算法去找出最佳降落地點。

回來的是三個檔案、一份 README、一張六面板圖表、一個可以拉滑桿的 HTML 圖版。

檔案內容請參考我的 Github 對應的專案連結


1. 這句話其實已經把題目定死了一半

Day 05 那邊有一個對照組 DEMO 2 ,提示詞是「幫我製作一個心理學的注意力遊戲」,完全沒提 Stroop、Flanker、Posner、Treisman,那四個派典是 Claude 自己挑的。

今天這句話正好相反,它把該用什麼寫死了。

  • 演算法:ICP、NDT。
  • 場景:太空、固體行星表面、降落之前。
  • 感測方式:光學掃描。
  • 要的答案:最佳降落地點。

所以 Claude 不用猜「這題該用什麼技術」,它只要決定中間缺的那幾塊,是我沒有自己實際做過的部分:

「用 ICP 對齊點雲」和「找出最佳降落地點」之間,還隔著一整條管線。

這條管線是它自己接起來的,我原本預期要提供更多資訊,或是會需要決定的實作方向。


2. Claude 自己補出來的管線

實際生出來的是六個階段:

[0] 合成行星表面真值地形(碎形基底 + 撞擊坑 + 岩塊 + 區域傾斜)
         │
   ┌─────┴─────┐
[1a] 軌道器      [1b] 下降段光學掃描
     先驗地圖          6 幀,高度 900 → 250 m
     =圖像對齊目標        導航位姿含漂移誤差
   └─────┬─────┘
[2] 點雲圖像對齊(ICP / NDT / Hybrid)→ 修正每一幀的位姿
[3] 多幀融合 → 0.5 m 解析度 DEM
[4] 危害分析:以 2.5 m 著陸足跡逐格做加權最小平方平面擬合
[5] 硬性約束 → 加權評分 → 非極大值抑制 → Top-5 候選點

有兩塊是我根本沒想到要有的。

第一塊是 [1a] 軌道器先驗地圖。 我原本的想像是「掃描好幾幀,然後把它們互相對齊」。這樣做只會得到一團內部一致、但不知道自己在哪裡的點雲。真正的地形相對導航(Terrain-Relative Navigation, TRN)是拿下降時掃到的地形,去對齊事先由軌道器測繪好的那份地圖,這樣才有絕對位置。

第二塊是 [0] 的真值地形。 它先生了一份「上帝視角」的地形,所有感測資料都是從這份真值取樣加雜訊來的。用處在最後才看得到:選完點之後,可以回頭拿真值驗證這個點到底安不安全。這是自己隨手寫的模擬最容易漏掉的東西,沒有真值就只能說「程式跑完了」,不能說「它做對了」。

至於為什麼非圖像對齊不可?因為如果直接相信慣性導航回報的位置,把六幀點雲疊起來,地圖空間的 RMSE 是 7.536 m;而 7 公尺的誤差疊在一份要判斷 0.3 m 岩塊的地形圖上,整張圖等於被塗糊掉,後面全部免談。


3. ICP 與 NDT 在做的事

兩個都是點雲圖像對齊的技術 (十年前就聽說過,並且當時看著學長與教授拿來實作一些很酷的東西):有兩坨具有三維座標的點,找出一組旋轉加平移,讓它們能緊貼在一起。差別在「怎麼定義貼得好不好」。

ICP 的做法很直覺:對來源點雲的每一個點,去目標點雲裡找最近的那個點,想辦法讓這些配對的距離 (高斯距離) 變小,反覆迭代。

這次生出來的版本用的是 point-to-plane,不量「點到點」的距離,改量「點到目標局部平面」的距離。理由:行星表面近似平面,point-to-plane 只懲罰法線方向的偏差、允許點沿著切平面滑動,收斂快一個數量級。

NDT 完全不同路:先把目標點雲切成一格一格的 voxel (所以如果拿來做腦 voxel 的定位會怎麼樣?),每一格用一個三維高斯分佈描述「這附近的表面長什麼樣」,整張目標地圖因此變成一個連續的機率場。圖像對齊於是變成「找一組位姿,讓來源點落在機率高的地方」,可以直接用梯度上升解,不必每次迭代都重找最近鄰。

Hybrid 則是先用 NDT 粗對位,再交給 ICP 精修。

原理我大致能理解,但從來沒有進行實作過,因為流程細節其實非常多:例如兩者都要對 SE(3) 做局部參數化、要推 Jacobian、要處理 Gauss-Newton 的正規方程。這部分 Claude 都做完了,而且刻意讓兩者共用同一組參數化與 Jacobian,原因是這樣兩者才能公平比較 (這句話等於 Claude 它是在自己給自己設實驗控制)。

在沒有現在的 LLM 之前,這些內容可能已經足夠做成碩論甚至博論的內容,而且可以應用到實際太空場域,例如火星的登陸等等。


4. 實測:這邊的實作結果與教科書不相符

程式跑完會印一張表,--seed 7,六幀掃描:

方法 地圖 RMSE 位姿誤差 @ 感測器 平均迭代 耗時 / 幀
未圖像對齊(純導航) 7.536 m
ICP 0.022 m 0.106 m / 0.05° 49 528 ms
NDT 1.369 m 1.427 m / 0.52° 43 5289 ms
Hybrid 0.022 m 0.109 m / 0.05° 47 465 ms

ICP 把 7.5 m 壓到 2.2 公分,NDT 停在 1.37 m。而 NDT 這個 1.37 m 不是平均意義上的「差一點」,是第 1 幀直接爛掉:逐幀看,NDT 在第 0、2、3、4、5 幀都在 0.03 m 上下,唯獨第 1 幀是 8.054 m,完全沒收斂,一幀就把平均拉爆。

再看收斂盆地。程式有一個 --sweep 模式,刻意給不同大小的初始誤差,每級跑 8 次,看多少次能收斂到 0.3 m 以內:

初始水平誤差 2 m 5 m 10 m 20 m 35 m
ICP 100% 100% 100% 62% 0%
NDT 100% 100% 75% 0% 0%

這次的 NDT 全面落後。 這邊的實作結果,跟印象中「NDT 的優勢就是收斂盆地比 ICP 寬、對初值比較不敏感」剛好相反。

Claude 自己把這件事寫進 README 了,而且給了解釋:

  1. 這版 ICP 用了對應距離退火(搜尋半徑從 8 m 逐步收到 0.8 m),等於是多解析度策略,初期容忍大位移、後期逼精度。NDT 靠金字塔換來的那個優勢,退火式 ICP 已經有了。
  2. 地形近似平面,NDT 的體素高斯在法線方向極薄,能提供的水平約束本來就弱。

然後它自己補了一句限制:「這個結論限於此類低起伏地形,不宜外推到城市或室內點雲。」

這一段是我覺得很誠實、不幻想的部分,不是因為結論多正確,而是因為它跑出了一個跟教科書說法不一致的結果,沒有試圖隱藏,也沒有回頭去調參數把 NDT 救到贏。前四天一直在對付的問題正好相反,模型在無法查證的欄位上瞎填、把不確定包裝成確定。

當然也有可能是它把 NDT 寫壞了,這點我沒有去另外獨立驗證,見文末註二。


5. 三個坑,全部不在提示詞裡

README 跟程式註解裡留了三個「實作時踩過的坑」。

坑一:姿態誤差不能給太大。

在 900 m 高度下,2° 的姿態誤差會透過力臂效應把點雲橫向甩開約 30 m,兩種演算法都會直接發散。

它的處理方式不是把演算法改強,是把參數改對:真實太空載具有星象儀,姿態知識精度遠優於 0.3°。所以預設值設成 nav_sigma_att_deg=0.25,並且註明「這不是限制,是把模型設對」。

坑二:NDT 需要共變異數膨脹退火,不然直接發散。

體素高斯在法線方向極薄(Σ_zz ~ 0.01 m²),初始誤差有好幾公尺的時候,指數項會直接下溢成零、梯度消失,NDT 連動都不會動。解法是在共變異數上加一個 σ₀²I 把高斯撐胖,再由粗到細逐級縮小,這等同對機率場做高斯平滑。

換句話說,教科書版的 NDT 在這個場景根本跑不起來,要加一層 annealing 才能用。

坑三:最大凸起的基準不能用視窗均值。

危害分析要算「著陸足跡範圍內最高的凸起有多高」,直覺是拿視窗內的高度減掉視窗均值。但這樣做,斜坡本身會被誤判成 0.5 m 級的凸起,全圖沒有任何一點合格。正確做法是減掉該格自己擬合出來的局部平面,坡度歸坡度、凸起歸凸起,兩個指標才不會互相汙染。

三個坑的共同點是:它們都不是「程式寫錯」,是題目本身的物理性質。


6. 從地形圖到「降落在哪裡」

圖像對齊完、融合成 0.5 m 的 DEM 之後,剩下的是選點。這一段反而是最像工程規格的部分:以 2.5 m 的著陸足跡半徑,逐格做加權最小平方平面擬合,抽出五個指標。

指標 為什麼重要 預設門檻
坡度 翻覆風險、推力向量餘裕 ≤ 10°
粗糙度(殘差 RMS) 著陸腳架接觸品質 ≤ 0.14 m
最大凸起 岩塊會頂穿或架空登陸艇 ≤ 0.30 m
資料覆蓋率 感測資料夠不夠可信 ≥ 75%
轉向距離 燃料代價 ≤ 30 m

任一項超標,分數直接歸零;其餘的加權平均成一個安全分數,最後做非極大值抑制(最小間隔 5 m),避免五個候選點全部擠在同一塊平地上。

https://ithelp.ithome.com.tw/upload/images/20260820/20161310x2WfLyXbf3.png

六個面板依序是:真值地形加掃描足跡與下降軌跡、圖像對齊後融合的 DEM、坡度圖(青色等值線是 10° 門檻)、粗糙度圖、安全分數與 Top-5 候選點、逐幀圖像對齊精度(對數座標)。

seed 7 的結果是:可著陸區域只有 319 m²,佔掃描範圍的 6.1%。第一名落在 (11.50, −5.50),估測坡度 1.83°、粗糙度 0.054 m。

再來是我覺得整份程式最關鍵的一行輸出,回頭拿真值地形驗證:

>>> 選定降落點: (11.50, -5.50) m
    真值地形驗證 -> 坡度 1.70 deg, 粗糙度 0.049 m  (估測值 1.83 deg / 0.054 m)

坡度差 0.13°、粗糙度差 5 mm。這一行的意義是:它不只跑完了,它證明了自己跑對了。


7. 最後又是一頁 HTML,但這次的角色不一樣

Day 05 的 HTML 是產出本身;今天的 HTML 是產出的後半段。

landing_site_plate.html 一樣是單一檔案、離線可開,但做法差很多:重的計算(圖像對齊、融合、平面擬合)已經在 Python 那邊算完、固化成資料,危害圖以 uint8 量化後 base64 內嵌進 HTML,門檻重算、評分、非極大值抑制則跑在瀏覽器端。

所以拉滑桿是即時的,不需要重跑那 15 秒的模擬。能動的東西有:

  • 五個硬性門檻滑桿(坡度/粗糙度/凸起/覆蓋率/轉向距離)
  • 五個評分權重滑桿(自動正規化)
  • 切換檢視:安全分數/限制因子/坡度/粗糙度/最大凸起
  • 點圖上任一處改設標稱目標點,轉向距離與虛線圓跟著重算

其中「限制因子」這個檢視我覺得設計得不錯:不可著陸區以對角影線標示,線的顏色就是最嚴重的那個超標項目,紅是坡度、紫是粗糙度、銅是凸起、灰是覆蓋率。一眼就能看出放寬哪個門檻才換得到面積。

這件事本來要靠反覆改參數重跑才做得到,現在變成拉一下滑桿。把「慢的部分算完固化、快的部分留給瀏覽器」,是這個做法值得筆記的一條。


8. 跟 Day 05 比,差在「可驗證性」

Day 05 收尾時整理出一條規律:畫面越像專業工具,免責就要寫得越用力。因為那三個 DEMO 的數據都是編的,介面卻在替它們做背書。

今天這個東西的體質不一樣。演算法是可查證的,ICP、NDT 都有原始論文,point-to-plane 的推導、NDT 的梯度與 Hessian 都能對照 Magnusson 2009;結果是可驗證的,有真值地形可以回頭對;失敗也是可重現的,換個 seed 再跑一次就行。
但可驗證不等於可信。README 最後那五條限制,我覺得比程式碼本身更重要,其中兩條特別致命:

  • 軌道器先驗地圖是從同一份真值地形取樣的,只有隨機雜訊、沒有系統性偏差。真實的 TRN 先驗地圖本身就有數公尺級的絕對定位誤差,圖像對齊精度會被那個誤差卡住。這是本模擬能達到公分級精度的主要原因。
  • 水平位置的可觀測性完全來自地形起伏。如果降落區極度平坦(像平滑的月海),ICP 跟 NDT 在水平方向都會退化成病態問題,得改用影像特徵匹配或都卜勒輔助。

也就是說,這份程式跑出 0.022 m,不代表真的登陸艇能做到 0.022 m,它示範的是演算法的行為,不是任務的性能。

這條界線跟 Day 05 講的「教學用的模擬,要對的是形狀,不是數值」是同一件事,只是今天這個東西長得更像真的,所以講清楚更重要。


9. 小結

  • 提示詞把「該用什麼」寫死,模型的工作就變成補中間缺的那幾塊,而那幾塊往往才是外行補不出來的部分(先驗地圖、真值驗證)。
  • 一份好的模擬要自帶真值。 沒有真值只能說「程式跑完了」,有真值才能說「它做對了」。
  • 跑出跟教科書不一致的結果時,把它寫出來並解釋,比把參數調到符合預期有價值得多。 這邊的實作在近平面地形上,NDT 輸給了退火式 ICP,這個落差本身比誰贏誰輸重要。
  • 卡住的地方常常是物理,不是程式。 姿態誤差的力臂效應、高斯在法線方向太薄、坡度汙染凸起,三個坑都不在我的提示詞裡。
  • 把慢的計算固化、把快的重算丟給瀏覽器,是讓參數探索從「重跑 15 秒」變成「拉滑桿」的關鍵。
  • 可驗證 ≠ 可信。 這份模擬的公分級精度有一半來自「先驗地圖太乾淨」這個假設,README 中有提及。

參考資料

點雲圖像對齊

地形相對導航與危害偵測避讓

註一:本文所有數字取自 descent_hda.py --seed 7 的執行(Python 3.13.9 / numpy 2.3.5 / scipy 1.16.3)。耗時欄位與機器有關,換一台會不一樣;RMSE 與成功率欄位在同一 seed 下可重現。收斂盆地表為每級 8 次試驗,樣本數很小,請當作定性觀察,不是統計證據。

註二:「NDT 在此場景收斂盆地不如 ICP」是這份實作跑出來的結果,不是通用結論。我沒有能力獨立驗證這版 NDT 的實作品質,也沒有拿 PCL 或 Open3D 的官方實作做對照,因此「是 NDT 本質如此」與「是這版 NDT 寫得不夠好」兩種可能都還開著,屬待確認。

註三:本程式是研究用途的模擬,不是飛控軟體。軌道器先驗地圖由同一份真值地形取樣而來、無系統性偏差,這是它能達到公分級精度的主要原因;光學感測被抽象成「已還原的 3D 點雲」,未模擬立體匹配失敗、低太陽角長陰影、塵埃反光等真實退化。任何真實任務的選點判斷都不應以本程式的輸出為依據。

註四:本文對 claude.ai 的功能描述以 2026 年 8 月 20 日的產品行為為準。

註五:本文提供的做法供參考,若有其他的看法或建議歡迎留言。


上一篇
Day 05|講不清楚的東西,就讓 Claude 做成一頁可以玩的網頁
系列文
三個介面,一套工作流?30 天 Claude 跨領域實戰:從 claude.ai、Claude Desktop 到 Claude Code6
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言